/**
 * MIT License
 * 
 * Copyright (c) 2024 - present @ ebraid
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#ifndef __EB_UUID_H__
#define __EB_UUID_H__

#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <lib/ctype.h>


#define UUID_SIZE 16


typedef struct {
	uint8_t blob[UUID_SIZE];
} guid_t;


typedef struct {
	uint8_t blob[UUID_SIZE];
} uuid_t;


#define GUID_INIT(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7)			\
((guid_t)								\
{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
   (b) & 0xff, ((b) >> 8) & 0xff,					\
   (c) & 0xff, ((c) >> 8) & 0xff,					\
   (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})


#define UUID_INIT(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7)			\
((uuid_t)								\
{{ ((a) >> 24) & 0xff, ((a) >> 16) & 0xff, ((a) >> 8) & 0xff, (a) & 0xff, \
   ((b) >> 8) & 0xff, (b) & 0xff,					\
   ((c) >> 8) & 0xff, (c) & 0xff,					\
   (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }})


/*
 * The length of a UUID string ("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee")
 * not including trailing NUL.
 */
#define	UUID_STRING_LEN		36

extern const guid_t guid_null;
extern const uuid_t uuid_null;


#ifdef __cplusplus
extern "C" {
#endif

static inline bool guid_equal(const guid_t *u1, const guid_t *u2)
{
	return memcmp(u1, u2, sizeof(guid_t)) == 0;
}

static inline void guid_copy(guid_t *dst, const guid_t *src)
{
	memcpy(dst, src, sizeof(guid_t));
}

static inline void import_guid(guid_t *dst, const uint8_t *src)
{
	memcpy(dst, src, sizeof(guid_t));
}

static inline void export_guid(uint8_t *dst, const guid_t *src)
{
	memcpy(dst, src, sizeof(guid_t));
}

static inline bool guid_is_null(const guid_t *guid)
{
	return guid_equal(guid, &guid_null);
}

static inline bool uuid_equal(const uuid_t *u1, const uuid_t *u2)
{
	return memcmp(u1, u2, sizeof(uuid_t)) == 0;
}

static inline void uuid_copy(uuid_t *dst, const uuid_t *src)
{
	memcpy(dst, src, sizeof(uuid_t));
}

static inline void import_uuid(uuid_t *dst, const uint8_t *src)
{
	memcpy(dst, src, sizeof(uuid_t));
}

static inline void export_uuid(uint8_t *dst, const uuid_t *src)
{
	memcpy(dst, src, sizeof(uuid_t));
}

static inline bool uuid_is_null(const uuid_t *uuid)
{
	return uuid_equal(uuid, &uuid_null);
}


/**
 * generate_random_uuid - generate a random UUID
 * @uuid: where to put the generated UUID
 *
 * Random UUID interface
 *
 * Used to create a Boot ID or a filesystem UUID/GUID, but can be
 * useful for other kernel drivers.
 */
void generate_random_uuid(unsigned char uuid[16]);


/**
 * @brief generate a random GUID
 * @guid: where to put the generated GUID
 * @return: none
 * @note: GUID is a 128-bit value, which is represented as a 16-byte array.
 *        the version is 4, and DCE is the variant.
 */
void generate_random_guid(unsigned char guid[16]);


/**
 * @brief generate a random GUID
 * @param lu: where to put the generated GUID
 * @return: none
 * @note: GUID is a 128-bit value, which is represented as a 16-byte array.
 *        the version is 4.
 */
extern void guid_gen(guid_t *u);


/**
 * @brief generate a random UUID
 * @param bu: where to put the generated UUID
 * @return: none
 * @note: UUID is a 128-bit value, which is represented as a 16-byte array.
 */
extern void uuid_gen(uuid_t *u);


/**
 * uuid_is_valid - checks if a UUID string is valid
 * @uuid:	UUID string to check
 *
 * Description:
 * It checks if the UUID string is following the format:
 *	xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
 *
 * where x is a hex digit.
 *
 * Return: true if input is valid UUID string.
 */
bool uuid_is_valid(const char *uuid);


extern const uint8_t guid_index[16];
extern const uint8_t uuid_index[16];


/**
 * @brief parse a UUID string to a GUID
 * @param uuid:	UUID string to parse
 * @param u:	where to put the parsed GUID
 * @return: 0 if success, -1 if failed
 */
int guid_parse(const char *uuid, guid_t *u);


/**
 * @brief parse a UUID string to a UUID
 * @param uuid:	UUID string to parse
 * @param u:	where to put the parsed UUID
 * @return: 0 if success, -1 if failed
 */
int uuid_parse(const char *uuid, uuid_t *u);


#ifdef __cplusplus
}
#endif


#endif // __EB_UUID_H__
